/*
                  Camera Class Implementation
*/

#include "Camera.h"

// Initialise static members
SDL_Rect Camera::map = SDL_Rect();
SDL_Rect Camera::view = SDL_Rect();
bool Camera::Bounded = false;
int Camera::iXPixelsPerSecond = 32;
int Camera::iYPixelsPerSecond = 32;
int Camera::iXMaxDistance = 32;
int Camera::iYMaxDistance = 32;
int Camera::iSnakeSpeed = 200;
Point Camera::Position = Point(0, 0);

Camera::Camera()
{

}

int Camera::Init(Point View, bool iBounded, SDL_Rect Map, const int& iSpeed)
{
    view.x = (int)View.x;
    view.y = (int)View.y;
    Bounded = iBounded;

    Position = Point(view.x, view.y);

    iXPixelsPerSecond = static_cast<int>((1000.0f / (float)iSpeed) * (float)TILE_WIDTH);
    iYPixelsPerSecond = static_cast<int>((1000.0f / (float)iSpeed) * (float)TILE_HEIGHT);

    iXMaxDistance = TILE_WIDTH;
    iYMaxDistance = TILE_HEIGHT;

    iSnakeSpeed = iSpeed;

    // The room should always have a size, if the camera is bounded
    if (Bounded == true && (Map.w == 0 || Map.h == 0))
    {
        printf("Warning: Camera: Room has no size\n");

        return -1;
    }
    else
    {
        map = Map;

        return 0;
    }
}

SDL_Rect Camera::Update(const SDL_Rect& Character)
{
    // Center the view on the center of the character
    view.x = Character.x + Character.w/2 - view.w/2;
    view.y = Character.y + Character.h/2 - view.h/2;

    // If the room is bounded, the view is ajusted to make sure that
    // it doesn't show what is outside the room. The ajustments are made
    // on the four borders.
    if (Bounded)
    {
        if (view.x < map.x)
            view.x = map.x;
        if (view.x + view.w > map.w)
            view.x = map.w - view.w;
        if (view.y < map.y)
            view.y = map.y;
        if (view.y + view.h > map.h)
            view.y = map.h - view.h;
    }

    Position.x = view.x;
    Position.y = view.y;

    return view;
}

SDL_Rect Camera::UpdateChase(const SDL_Rect& Character, const int& iDirection, const int& iFrameTime)
{
    double dFrameSeconds = (double)iFrameTime / (double)1000;
    double dXMovement = (double)iXPixelsPerSecond * dFrameSeconds;
    double dYMovement = (double)iYPixelsPerSecond * dFrameSeconds;

    Point Focus = GetFocus();
    Point CharCenter = Point(Character.x + (Character.w/2), Character.y + (Character.h/2));

    int iDifference;

    if (Focus.x < CharCenter.x)
    {
        iDifference = (int)CharCenter.x - (int)Focus.x;

        if (iDifference < dXMovement)
        {
            Position.x += iDifference;
        }
        else
        {
            Position.x += dXMovement;
        }
    }
    else // Focus.x > CharCenter.x
    {
        iDifference = (int)Focus.x - (int)CharCenter.x;

        if (iDifference < dXMovement)
        {
            Position.x -= iDifference;
        }
        else
        {
            Position.x -= dXMovement;
        }
    }

    if (Focus.y < CharCenter.y)
    {
        iDifference = (int)CharCenter.y - (int)Focus.y;

        if (iDifference < dYMovement)
        {
            Position.y += iDifference;
        }
        else
        {
            Position.y += dYMovement;
        }
    }
    else // Focus.y > CharCenter.y
    {
        iDifference = (int)Focus.y - (int)CharCenter.y;

        if (iDifference < dYMovement)
        {
            Position.y -= iDifference;
        }
        else
        {
            Position.y -= dYMovement;
        }
    }

    view.x = (int)Position.x;
    view.y = (int)Position.y;

    //cout << GetFocus().x << ":" << GetFocus().y << ":" << Character.x << ":" << Character.y << endl;
    //cout << GetFocus().DistanceFromPoint(Point(Character.x + (Character.w/2), Character.y + (Character.h/2))) << endl;

    if ((int)Focus.DistanceFromPoint(CharCenter) >= (iXMaxDistance*2))
    {
        return Update(Character);
    }

    return view;
}

Point Camera::GetFocus()
{
    return Point(view.x + (view.w / 2), view.y + (view.h / 2));
}

SDL_Rect& Camera::GetMap()
{
    return map;
}

SDL_Rect& Camera::GetView()
{
    return view;
}

bool Camera::IsBounded()
{
    return Bounded;
}

void Camera::SetBound(bool iBound)
{
    Bounded = iBound;
}
